/** ****************************************************************************
@defgroup UART UART
@ingroup BSP
@brief 串口驱动
@addtogroup UART
@{
*******************************************************************************/

#include "stdinc.h"
#include "driver/uart.h"
#include "uart.h"
#include "c_call_cpp_bridge.h"

#define LOGTAG "SZW:UART"


/// ESP32 有 3 个 UART
static struct stUARTPort _UART0 = {
	UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, NULL, NULL, UART_MODE_UART,
	{ 115200, UART_DATA_8_BITS, UART_STOP_BITS_1, UART_PARITY_DISABLE, UART_HW_FLOWCTRL_DISABLE, 122, UART_SCLK_APB },
	NULL, NULL, FALSE, NULL
};

static struct stUARTPort _UART1 = {
	UART_NUM_1, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, NULL, NULL, UART_MODE_UART,
	{ 115200, UART_DATA_8_BITS, UART_STOP_BITS_1, UART_PARITY_DISABLE, UART_HW_FLOWCTRL_DISABLE, 122, UART_SCLK_APB },
	NULL, NULL, FALSE, NULL
};

static struct stUARTPort _UART2 = {
	UART_NUM_2, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, NULL, NULL, UART_MODE_UART,
	{ 115200, UART_DATA_8_BITS, UART_STOP_BITS_1, UART_PARITY_DISABLE, UART_HW_FLOWCTRL_DISABLE, 122, UART_SCLK_APB },
	NULL, NULL, FALSE, NULL
};

UARTPort UARTPort0 = &_UART0;
UARTPort UARTPort1 = &_UART1;
UARTPort UARTPort2 = &_UART2;


// 串口异步事件回调函数
static void uartAsyncSemaphoreHandler(QueueHandle_t queue, UARTPort uart) {
    uart_event_t event;
    uart_event_type_t type;
    uint8_t ch, data[UART_FIFO_LEN];
    int i, len;

    // 读取事件(这里不应该阻塞！)
    if(!xQueueReceive(queue, (void*)&event, 0)) {
    	logw("uartAsyncSemaphoreHandler blocked ?!");
    	return;
    }
    type = event.type; len = event.size;
    //log("uart%d event = %d", uart->port, type);

	switch(type) {
		case UART_DATA: {
			if(!uart->enableRxHandler || !uart->onRxChar) { break; }
			//log("uart received data (len=%d):", len);
			uart_read_bytes(uart->port, data, len, portMAX_DELAY);
			//dumpBin(data, len);

			// 逐个字符调用回调函数
			for(i=0; i<len; i++) {
				ch = data[i];//UREG_FIFO_RW(uart);
				uart->onRxChar(uart, ch, uart->onRxCharCookie);
			}
			break;
		}
		case UART_FIFO_OVF: {
			log("uart%d: hw fifo overflow", uart->port);
			uart_flush_input(uart->port);
			xQueueReset(queue);
			break;
		}
		case UART_BUFFER_FULL: {
			log("uart%d ring buffer full", uart->port);
			uart_flush_input(uart->port);
			xQueueReset(queue);
			break;
		}
		case UART_BREAK:       log("uart%d rx break", uart->port); break;
		case UART_PARITY_ERR:  log("uart%d parity error", uart->port); break;
		case UART_FRAME_ERR:   log("uart%d frame error", uart->port); break;
		case UART_PATTERN_DET: log("uart%d pattern detected", uart->port); break;
		default:               log("uart%d unhandled event: %d", uart->port, type); break;
	}
}

esp_err_t UART_init(
	UARTPort uart, int pinTxd, int pinRxd, void *led, FUNC_void_u8 txe, uart_mode_t mode,
	uint32_t baudrate, uart_word_length_t dataBits, uart_parity_t stopBits, uart_stop_bits_t parity,
	bool initForAsync)
{
	esp_err_t err = ESP_OK;

	uart->pinTxd = pinTxd; uart->pinRxd = pinRxd; uart->txe = txe; uart->led = led;
	uart->config.baud_rate = baudrate;
	uart->config.data_bits = dataBits;
	uart->config.stop_bits = stopBits;
	uart->config.parity = parity;

    // Configure UART parameters
	RET_ON_ERROR( uart_param_config(uart->port, &uart->config) );
    // Set UART1 pins
	RET_ON_ERROR( uart_set_pin(uart->port, uart->pinTxd, uart->pinRxd, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE) );

	do {
		// 是否初始化为异步模式
		if(initForAsync) {
			// 加载系统默认的串口驱动，指定需要串口事件队列
			RET_ON_ERROR( uart_driver_install(uart->port, 256, 0, 32, &uart->queue, 0) );

			// 添加串口事件队列监听任务
			err = osTaskRunOnSemaphore((QueueSetMemberHandle_t)uart->queue, (OSTaskSemaphoreHandler)uartAsyncSemaphoreHandler, uart);
			if(err) { break; }
		} else {
			// 加载系统默认的串口驱动，不需要串口事件队列
			RET_ON_ERROR( uart_driver_install(uart->port, 256, 0, 0, NULL, 0) );
		}

		// 加载系统默认的串口驱动后，必须要设置串口工作模式
		err = uart_set_mode(uart->port, uart->mode);
		if(err) { break; }

		return ESP_OK;
	} while(0);

	// 如果失败，则必须删除驱动
	return uart_driver_delete(uart->port);
}

void UART_close(UARTPort uart) {
	uart_driver_delete(uart->port);
}

esp_err_t UART_enableIrqRx(UARTPort uart, FUNC_UART_onRxChar onRxChar, const void *onRxCharCookie) {
	if(!uart) { return ESP_ERR_INVALID_ARG; }
	if(!uart->queue) { return ESP_FAIL; }
	if(onRxChar || onRxCharCookie) { uart->onRxChar = onRxChar; uart->onRxCharCookie = (void*)onRxCharCookie; }
	if(uart->onRxChar || uart->onRxCharCookie) { uart->enableRxHandler = TRUE; }
	return ESP_OK;
}

esp_err_t UART_disableIrqRx(UARTPort uart) {
	uart->enableRxHandler = FALSE;
	return ESP_OK;
}

int UART_putc(UARTPort uart, uint8_t ch) {
	if(!uart) { return -1; }
	//return UART_putc2(uart, ch);
	return uart_tx_chars(uart->port, (const char*)&ch, 1);
}

int UART_getc(UARTPort uart, uint8_t *ch) {
	if(!uart) { return -1; }
	//return UART_getc2(uart, ch);
	return uart_read_bytes(uart->port, ch, 1, (1000 / portTICK_RATE_MS));
}

int UART_send(UARTPort uart, const void* data, int len) {
	if(!uart || !data || !len) { return -1; }
	if(uart->txe) { uart->txe(ON); }
	//len = UART_send2(uart, data, len);
	len = uart_write_bytes(uart->port, data, len);
	if(uart->txe) { uart->txe(OFF); }
	return len;
}

int UART_receive(UARTPort uart, void* buff, int buffSize, const char *okFlag, const char *failedFlag, uint16_t timeoutTotal, uint16_t timeoutInterval) {
	if(!uart || !buff || !buffSize) { return -1; }
	buffSize--;	// 留一个位置给尾部 '\0'

	// 同步接收数据时，应关闭接收中断，防止数据被中断服务程序读走了
	UART_disableIrqRx(uart);

	uint32_t start = osGetMs();
	uint32_t lastByteTime = 0;
	int ret, len = 0;
	uint8_t ch = 0;
	char *data = (char*)buff;
	data[0] = '\0';

	while(1) {
		ret = UART_getc(uart, &ch);
		if(ret > 0) {
			// 收到数据
			data[len++] = ch;
			lastByteTime = osGetMs();

			// 因缓冲区满中止
			if(len >= buffSize) { break; }
			// 因 OK 标志中止
			if(okFlag && strstr(data, okFlag)) { break; }
			// 因 Failed 标志中止
			if(failedFlag && strstr(data, failedFlag)) { break; }
		}

		// 因总超时中止
		if(timeoutTotal && (osElapsedMs(start) >= timeoutTotal)) { break; }
		// 因间隔超时中止
		if(timeoutInterval && lastByteTime && (osElapsedMs(lastByteTime) >= timeoutInterval)) { break; }

		// 喂看门狗，并延时一下
		osFeedWatchdog(); osDelayUs(10);
	}

	// 接收完成，使能中断处理
	UART_enableIrqRx(uart, NULL, NULL);

	data[len] = '\0';
	return len;
}

int UART_cmdResponse(UARTPort uart, char *cmd, void* buff, int buffSize, char *okFlag, char *failedFlag, uint16_t timeoutTotal, uint16_t timeoutInterval) {
	int len = UART_send(uart, cmd, strlen(cmd));
	if(len < 0) { return len; }
	return UART_receive(uart, buff, buffSize, okFlag, failedFlag, timeoutTotal, timeoutInterval);
}

static uart_word_length_t charToDataBits(char val) {
	if(val == '5') { return UART_DATA_5_BITS; }
	if(val == '6') { return UART_DATA_6_BITS; }
	if(val == '7') { return UART_DATA_7_BITS; }
	return UART_DATA_8_BITS;
}

static uart_parity_t charToParity(char val) {
	if(val == 'e') { return UART_PARITY_EVEN; }
	if(val == 'o')  { return UART_PARITY_ODD; }
	return UART_PARITY_DISABLE;
};

static uart_stop_bits_t charToStopBits(char val) {
	if(val == '2') { return UART_STOP_BITS_2; }
	return UART_STOP_BITS_1;
};

esp_err_t UART_parseParam(char* param, uart_config_t* config) {
	int baud;
	char dataBits = '8', parity = 'n', stopBits = '1';
	int ret = sscanf(param, "%d,%c,%c,%c", &baud, &dataBits, &parity, &stopBits);
	if(ret < 1) { return ESP_ERR_INVALID_ARG; }

	config->baud_rate = baud;
	config->data_bits = charToDataBits(dataBits);
	config->parity = charToParity(parity);
	config->stop_bits = charToStopBits(stopBits);
	return ESP_OK;
}

static char dataBitsToChar(uart_word_length_t val) {
	if(val == UART_DATA_5_BITS) { return '5'; }
	if(val == UART_DATA_6_BITS) { return '6'; }
	if(val == UART_DATA_7_BITS) { return '7'; }
	return '8';
}

static char parityToChar(uart_parity_t val) {
	if(val == UART_PARITY_EVEN) { return 'e'; }
	if(val == UART_PARITY_ODD)  { return 'o'; }
	return 'n';
};

static char stopBitsToChar(uart_stop_bits_t val) {
	if(val == UART_STOP_BITS_2) { return '2'; }
	return '1';
};

esp_err_t UART_packParam(uart_config_t* config, char* param) {
	snprintf(param, 16, "%d,%c,%c,%c", config->baud_rate, dataBitsToChar(config->data_bits), parityToChar(config->parity), stopBitsToChar(config->stop_bits));
	return ESP_OK;
}


/**
 * 异步处理相关
 */
/*
#define UART_EMPTY_THRESH_DEFAULT  (10)
#define UART_FULL_THRESH_DEFAULT  (120)
#define UART_TOUT_THRESH_DEFAULT   (10)

#define RX_INT_MASK  (UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M | UART_RXFIFO_OVF_INT_ENA_M)
#define TX_INT_MASK  (UART_TX_DONE_INT_ENA_M | UART_TXFIFO_EMPTY_INT_ENA_M)
#define ERR_INT_MASK (UART_FRM_ERR_INT_ENA_M | UART_BRK_DET_INT_ENA_M | UART_PARITY_ERR_INT_ENA_M)

// 串口寄存器相关定义
static DRAM_ATTR uart_dev_t* const UART[UART_NUM_MAX] = {&UART0, &UART1, &UART2};
#define UARTREG(uart)          (UART[uart->port])
#define UREG_INT_ENA(uart)     (UART[uart->port]->int_ena.val)
#define UREG_INT_CLEAR(uart)   (UART[uart->port]->int_clr.val)
#define UREG_INT_RAW(uart)     (UART[uart->port]->int_raw.val)
#define UREG_INT_STATE(uart)   (UART[uart->port]->int_st.val)
#define UREG_FIFO_RW(uart) 	(UART[uart->port]->fifo.rw_byte)
#define UREG_STATUS(uart) 		(UART[uart->port]->status)

#define USTATUS_RXFIFO_CNT(uart)	(UREG_STATUS(uart).rxfifo_cnt)
#define USTATUS_TXFIFO_CNT(uart)	(UREG_STATUS(uart).txfifo_cnt)


static int UART_putc2(UARTPort uart, uint8_t ch) {
	int time;
	osDelayMsWhile(time, 1000, (USTATUS_TXFIFO_CNT(uart) >= UART_FIFO_LEN));
	if(!time) {	return -1; }
	UREG_FIFO_RW(uart) = ch;
	return 1;
}

int UART_getc2(UARTPort uart, uint8_t *ch) {
	int time;
	osDelayMsWhile(time, 1000, (USTATUS_RXFIFO_CNT(uart) < 1));
	if(!time) {	return 0; }
	*ch = UREG_FIFO_RW(uart);
	return 1;
}

int UART_send2(UARTPort uart, const void* data, int len) {
    uint8_t* bytes = (uint8_t*)data;
    for(; len>0; len--) {
        UART_putc2(uart, *(bytes++));
    }
    return len;
}

static void irqHandler(void *cookie) {
	UARTPort uart = (UARTPort)cookie;
    uint32_t uart_intr_status = 0;
    int rx_fifo_len = 0;
    uint8_t ch = 0;

    switchOn(uart->led);

    while(1) {
        uart_intr_status = UREG_INT_STATE(uart);

        // 没有其它中断了，返回
        if(uart_intr_status == 0) {
        	break;
        } else if(uart_intr_status & RX_INT_MASK) {
        	// RX FIFO 中的数据长度
            rx_fifo_len = USTATUS_RXFIFO_CNT(uart);
        	// 读取 RX FIFO 中的所有数据以清除中断
            for(; rx_fifo_len > 0; rx_fifo_len--) {
            	ch = UREG_FIFO_RW(uart);
            }
        } else if(uart_intr_status & TX_INT_MASK) {
			// 清除 TX 中断
        	UREG_INT_CLEAR(uart) = TX_INT_MASK;
        } else {
			// 清除其它所有中断
        	UREG_INT_CLEAR(uart) = uart_intr_status;
    	}
    }

    switchOff(uart->led);
}

// 初始化为异步模式
static esp_err_t initAsync(UARTPort uart) {
	esp_err_t err = ESP_OK;
	uint32_t intMask = (uart->onRxChar ? RX_INT_MASK : 0) | (uart->onTxComplete ? TX_INT_MASK : 0);

	if(uart->intr) {
		// 如果已经初始化过，则重新设置中断掩码并返回
		return uart_enable_intr_mask(uart->port, intMask);
	}

	// 注册中断处理函数
	RETLOG_ERROR( uart_isr_register(uart->port, irqHandler, uart, 0, &uart->intr) );

	do {
		// 配置中断
		uart_intr_config_t config = {
			.intr_enable_mask =	intMask,
			.rx_timeout_thresh = UART_TOUT_THRESH_DEFAULT,
			.rxfifo_full_thresh = UART_FULL_THRESH_DEFAULT,
			.txfifo_empty_intr_thresh = UART_EMPTY_THRESH_DEFAULT
		};
		err = uart_intr_config(uart->port, &config);
		if(err) { break; }

		return ESP_OK;
	} while(0);

	esp_intr_free(uart->intr);
	return err;
}

esp_err_t UART_enableIrqRx(UARTPort uart, FUNC_UART_onRxChar onRxChar, const void *onRxCharCookie) {
	if(!uart) { return ESP_ERR_INVALID_ARG; }
	if(onRxChar) { uart->onRxChar = onRxChar; uart->onRxCharCookie = (void*)onRxCharCookie; }
	return initAsync(uart);
}

esp_err_t UART_enableIrqTx(UARTPort uart, FUNC_UART_onTxComplete onTxComplete, const void *onTxCompleteCookie) {
	if(!uart) { return ESP_ERR_INVALID_ARG; }
	if(onTxComplete) { uart->onTxComplete = onTxComplete; uart->onTxCompleteCookie = (void*)onTxCompleteCookie; }
	return initAsync(uart);
}

void UART_disableIrqRx(UARTPort uart) {
	uart_disable_intr_mask(uart->port, RX_INT_MASK);
}

void UART_disableIrqTx(UARTPort uart) {
	uart_disable_intr_mask(uart->port, TX_INT_MASK);
}
*/


/// @}
